﻿''Copyright 2008 Dr. Zoidberg
' 
'Licensed under the Apache License, Version 2.0 (the "License");
'you may not use this file except in compliance with the License.
'You may obtain a copy of the License at
'
'	http://www.apache.org/licenses/LICENSE-2.0 
'
'Unless required by applicable law or agreed to in writing, software 
'distributed under the License is distributed on an "AS IS" 
'BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
'See the License for the specific language governing permissions 
'and limitations under the License. 
'
'Original code by arik poznanski www.codeproject.com/kb/trace/minememoryreader.aspx
'modified by dr. zoidberg to add memory writing capability

Imports System
Imports System.Diagnostics
Imports System.Runtime.InteropServices

Namespace ProcessMemoryReaderWriterLib

    Public Class ProcessMemoryReaderWriterApi
        Public Const PROCESS_VM_READ As UInteger = &H10I
        Public Const PROCESS_VM_WRITE As UInteger = &H20I
        Public Const PROCESS_VM_OPERATION As UInteger = &H8I

        <DllImport("kernel32.dll")> _
        Public Shared Function OpenProcess(ByVal dwDesiredAccess As UInt32, ByVal bInheritHandle As Int32, ByVal dwProcessId As UInt32) As IntPtr
        End Function

        <DllImport("kernel32.dll")> _
        Public Shared Function CloseHandle(ByVal hObject As IntPtr) As Int32
        End Function

        <DllImport("kernel32.dll", setlasterror:=True)> _
        Public Shared Function ReadProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, <[In](), Out()> _
ByVal buffer As Byte(), ByVal size As UInt32, ByRef lpNumberOfBytesRead As IntPtr) As Int32
        End Function

        <DllImport("kernel32.dll", setlasterror:=True)> _
        Public Shared Function VirtualAllocEx(ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As UInteger, _
                                              ByVal flAllocationType As UInteger, ByVal flProtect As UInteger) As IntPtr
        End Function

        <DllImport("kernel32.dll", setlasterror:=True)> _
        Public Shared Function WriteProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByVal lpBuffer As Byte(), _
                                                  ByVal nSize As UIntPtr, <Out()> ByRef lpNumberOfBytesWritten As IntPtr) As Boolean
        End Function

        <DllImport("kernel32.dll", setlasterror:=True)> _
        Public Shared Function VirtualFreeEx(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByVal dwSize As UIntPtr, ByVal dwFreeType As UInteger) As Boolean
        End Function
    End Class

    Public Class ProcessMemoryReaderWriter

        Public Sub New()
        End Sub

        Public Property ReadWriteProcess() As Process
            Get
                Return m_ReadProcess
            End Get
            Set(ByVal value As Process)
                m_ReadProcess = value
            End Set
        End Property

        Private m_ReadProcess As Process = Nothing
        Private m_hProcess As IntPtr = IntPtr.Zero

        Public Sub OpenProcess()
            m_hProcess = ProcessMemoryReaderWriterApi.OpenProcess(ProcessMemoryReaderWriterApi.PROCESS_VM_READ Or ProcessMemoryReaderWriterApi.PROCESS_VM_WRITE Or ProcessMemoryReaderWriterApi.PROCESS_VM_OPERATION , 1, CInt(m_ReadProcess.Id))
        End Sub

        Public Sub CloseHandle()
            Dim iRetValue As Integer
            iRetValue = ProcessMemoryReaderWriterApi.CloseHandle(m_hProcess)
            If iRetValue = 0 Then
                Throw New Exception("CloseHandle failed")
            End If
        End Sub

        Public Function ReadProcessMemory(ByVal MemoryAddress As IntPtr, ByVal bytesToRead As UInteger, ByRef bytesReaded As Integer) As Byte()
            Dim buffer As Byte() = New Byte(bytesToRead - 1) {}

            Dim ptrBytesReaded As IntPtr
            If ProcessMemoryReaderWriterApi.ReadProcessMemory(m_hProcess, MemoryAddress, buffer, bytesToRead, ptrBytesReaded) = 0 Then
                Trace.WriteLine("ReadProcessMemory: " & New ComponentModel.Win32Exception().Message)
            End If

            bytesReaded = ptrBytesReaded.ToInt32()

            Return buffer
        End Function

        Public Function AllocateAndWriteData(ByRef datablock As Byte()) As IntPtr
            Dim retPtr As New IntPtr(0)

            retPtr = ProcessMemoryReaderWriterApi.VirtualAllocEx(m_hProcess, New IntPtr(0), datablock.Length, &H1000I Or &H2000I, &H4I)

            If retPtr.ToInt32 <> 0 Then
                If ProcessMemoryReaderWriterApi.WriteProcessMemory(m_hProcess, retPtr, datablock, datablock.Length, New IntPtr(0)) = 0 Then
                    retPtr = New IntPtr(0)
                    Trace.WriteLine("WriteProcessMemory: " & New ComponentModel.Win32Exception().Message)
                End If
            Else
                Trace.WriteLine("VirtualAllocEx: " & New ComponentModel.Win32Exception().Message)
            End If

            Return retPtr
        End Function

        Public Function DeallocateBlock(ByVal blockAddr As IntPtr) As Boolean
            If ProcessMemoryReaderWriterApi.VirtualFreeEx(m_hProcess, blockAddr, 0, &H8000I) = 0 Then
                Trace.WriteLine("VirtualFreeEx: " & New ComponentModel.Win32Exception().Message)
                Return False
            End If
            Return True
        End Function
    End Class

End Namespace